/** @file    FormPersistenceManager.cpp
 *  @author  Alessandro Polo
 *  @version $Id: FormPersistenceManager.cpp 2867 2010-08-07 20:44:51Z alex $
 *  @brief
 * File containing methods for the wosh::gui::FormPersistenceManager class.
 * The header for this class can be found in FormPersistenceManager.h, check that file
 * for class description.
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

 #include "FormPersistenceManager.h"
 #include "ui_FormPersistenceManager.h"
 #include <core/PersistenceManager.h>
 #include <core/ObjectFactory.h>
 #include <core/List.h>
 #include <framework/gui/GuiUtilities.h>
 #include <framework/gui/dialogs/GuiDialogs.h>

 #include <QtGui/QInputDialog>
 #include <QtGui/QMessageBox>


using namespace std;
namespace wosh {
 namespace gui {

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////


 WOSH_REGISTER(wosh::gui::FormPersistenceManager, "wosh::gui::IWidgetGeneric", 1.0, _static_FormPersistenceManager )
 WOSH_GUI_MAP(wosh::gui::FormPersistenceManager, "wosh::PersistenceManager", 0.0, _static_Map_FormPersistenceManager )

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

FormPersistenceManager::FormPersistenceManager(QWidget *parent)
	: IWidgetGeneric(parent) {
	this->m_ui = new Ui::FormPersistenceManager();
	this->m_ui->setupUi(this);

	IWidgetGeneric::setTargetURI(_PersistenceManager_URI);
	buildMenus();

	// tab Installed DataBases [0]
	this->m_ui->tableViewDataBases->setMethodList(_PersistenceManager_METHOD_DataBases_list);
	this->m_ui->tableViewDataBases->getTableView()->setContextMenuPolicy(Qt::CustomContextMenu);
	connect(this->m_ui->tableViewDataBases, SIGNAL(postMessage(Message*)),this, SLOT(postMessage(Message*)) );
	connect(this->m_ui->tableViewDataBases, SIGNAL(tableContextMenuRequested(const QPoint&, const QModelIndex&)),this, SLOT(tableViewDataBases_ContextMenu(const QPoint&, const QModelIndex&)) );
	connect(this->m_ui->btnDbForceSave, SIGNAL(clicked()), this, SLOT(btnDbForceSave_clicked()));


	// tab Installed Protocols [1]
	this->m_ui->tableViewProtocols->setMethodList(_PersistenceManager_METHOD_Protocols_list);
	this->m_ui->tableViewProtocols->getTableView()->setContextMenuPolicy(Qt::CustomContextMenu);
	connect(this->m_ui->tableViewProtocols, SIGNAL(postMessage(Message*)),this, SLOT(postMessage(Message*)) );
	connect(this->m_ui->tableViewProtocols, SIGNAL(tableContextMenuRequested(const QPoint&, const QModelIndex&)),this, SLOT(tableViewProtocols_ContextMenu(const QPoint&, const QModelIndex&)) );
	connect(this->m_ui->btnProtocolUninstall, SIGNAL(clicked()), this, SLOT(btnProtocolUninstall_clicked()));

	// tab Supported Protocols [2]
	this->m_ui->tableViewSupportedProtocols->setMethodList(_PersistenceManager_METHOD_ListSupportedProtocols);
	//this->m_ui->tableViewSupportedProtocols->getTableView()->setContextMenuPolicy(Qt::CustomContextMenu);
	connect(this->m_ui->tableViewSupportedProtocols, SIGNAL(postMessage(Message*)),this, SLOT(postMessage(Message*)) );
	//connect(this->m_ui->tableViewSupportedProtocols, SIGNAL(tableContextMenuRequested(const QPoint&, const QModelIndex&)),this, SLOT(tableViewSupportedProtocols_ContextMenu(const QPoint&, const QModelIndex&)) );
	connect(this->m_ui->btnProtocolInstall, SIGNAL(clicked()), this, SLOT(btnProtocolInstall_clicked()));

	// tab Encoders [4]
	this->m_ui->cmbProtocols->setModel(this->m_ui->tableViewProtocols->getTableModel());
	this->m_ui->cmbProtocols->setModelColumn(0);
	connect(this->m_ui->cmbProtocols, SIGNAL(currentIndexChanged(int)), this, SLOT(refreshEncoders()));
	this->m_ui->tableViewEncoders->setContextMenuPolicy(Qt::CustomContextMenu);
	//connect(this->m_ui->tableViewSupportedProtocols, SIGNAL(customContextMenuRequested(const QPoint&)),this, SLOT(tableViewSupportedProtocols_ContextMenu(const QPoint&)) );
	connect(this->m_ui->tableViewEncoders->getUpdateBar(), SIGNAL(updateClicked()), this, SLOT(refreshEncoders()));

	// tab SandBox [5]
	this->sand_obj = NULL; this->sand_obj_gui = NULL;
	this->sand_buffer = NULL; this->sand_buffer_size = 0;
	this->sand_obj_types_model = new ObjectTypeInfoListModel(this);
	this->m_ui->cmbSandObjectType->setModel(sand_obj_types_model);
	connect(this->m_ui->btnSandObjectAllocate, SIGNAL(clicked()), this, SLOT(btnSandObjectAllocate_clicked()));
	connect(this->m_ui->btnSandObjectDestroy, SIGNAL(clicked()), this, SLOT(btnSandObjectDestroy_clicked()));
	connect(this->m_ui->btnSandObjectGui, SIGNAL(clicked()), this, SLOT(btnSandObjectGui_clicked()));
	connect(this->m_ui->btnSandObjectTypeListRefresh, SIGNAL(clicked()), this, SLOT(refreshSandObjectTypeList()));

	connect(this->m_ui->btnSandToString, SIGNAL(clicked()), this, SLOT(btnSandToString_clicked()));
	connect(this->m_ui->btnSandEncode, SIGNAL(clicked()), this, SLOT(btnSandEncode_clicked()));
	connect(this->m_ui->btnSandDecode, SIGNAL(clicked()), this, SLOT(btnSandDecode_clicked()));
 }

FormPersistenceManager::~FormPersistenceManager() {
	delete this->m_ui;

	if ( this->sand_obj != NULL ) {
		ObjectFactory::destroy(this->sand_obj);
		this->sand_obj = NULL;
	 }
	if ( this->sand_buffer != NULL ) {
		delete [] this->sand_buffer; this->sand_buffer = NULL;
	 }

 }

void FormPersistenceManager::changeEvent(QEvent *e) {
	QWidget::changeEvent(e);
	if ( e->type() == QEvent::LanguageChange )
		this->m_ui->retranslateUi(this);
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void FormPersistenceManager::refreshAll() {
	this->setWindowTitle( QString("Persistence Manager [%1]").arg(this->getTargetURI().getKernelName().c_str()) );
	this->m_ui->tableViewDataBases->refreshData();
	this->m_ui->tableViewProtocols->refreshData();
	this->m_ui->tableViewSupportedProtocols->refreshData();
 	refreshSandObjectTypeList();
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void FormPersistenceManager::refreshEncoders() {
	QString encoder_name = this->m_ui->cmbProtocols->currentText();
	Message* message = new Message(new Request(_METHOD_List));
	message->getDestination().setParent( this->getTargetURI() );
	message->getDestination().getPath().push_back("Protocols");
	message->getDestination().setName(	encoder_name.toStdString() );
	postMessageForTarget( message );
	this->m_ui->tableViewEncoders->getUpdateBar()->sayRetrieving();
 }

void FormPersistenceManager::refreshSandObjectTypeList() {
	this->sand_obj_types_model->getData().clear();
	WRESULT ret = ObjectFactory::findChildsOf( this->sand_obj_types_model->getData(), "wosh::ISerializable", 0.0, true );
	if ( WFAILED(ret) ) {
		QMessageBox::critical(this, tr("Listing Serializable types.."), tr("FAILED. Error#%1 gathering list.").arg(ret) );
	 }
	this->sand_obj_types_model->reset();
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void FormPersistenceManager::btnDbForceSave_clicked() {
	Variant bundleName = this->m_ui->tableViewDataBases->getCurrentItemAsVariantAtCol(0);
	List* args = new List(2);
	args->push_back( bundleName.clone() );
	args->push_back<Variant>( "uninstall" );
	//executeRemoteMethod( _PersistenceManager_METHOD_control_bundle, args );
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void FormPersistenceManager::btnProtocolUninstall_clicked() {
	Variant protoName = this->m_ui->tableViewProtocols->getCurrentItemAsVariantAtCol(0);
	List* args = new List(2);
	args->push_back( protoName.clone() );
	args->push_back<Variant>( "uninstall" );
//	executeRemoteMethod( _PersistenceManager_METHOD_control_bundle, args );
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void FormPersistenceManager::btnProtocolInstall_clicked() {
	Variant bundleType = this->m_ui->tableViewSupportedProtocols->getCurrentItemAsVariantAtCol(0);
	executeRemoteMethod( _PersistenceManager_METHOD_LoadProtocol, bundleType.clone() );
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void FormPersistenceManager::checkAllocateSandBuffer() {
	if ( this->sand_buffer != NULL ) return;
	this->sand_buffer_size = 32000;
	this->sand_buffer = new char[this->sand_buffer_size];
 }

void FormPersistenceManager::btnSandObjectAllocate_clicked() {
	if ( this->sand_obj != NULL ) {
		QMessageBox::warning(this, tr("Allocate SandObject.."), tr("FAILED. Destroy current object before allocating a new one.") );
		return;
	 }
	this->sand_obj = ObjectFactory::createTypeOf<ISerializable>( this->m_ui->cmbSandObjectType->currentText().toStdString(), 0.0);
	if ( this->sand_obj == NULL ) {
		QMessageBox::critical(this, tr("Allocate SandObject.."), tr("FAILED. Unable to allocate object!") );
		this->m_ui->lblSandObjectStatus->setText( tr("Status: IDLE") );
		this->m_ui->cmbSandEncoders->clear();
		return;
	 }
	this->m_ui->lblSandObjectStatus->setText( tr("Status: ALLOCATED %1").arg(this->sand_obj->getClassName()) );

	std::vector<std::string> encoders_name;
	PersistenceManager::getEncoderProtocolsFor( encoders_name, this->sand_obj->getClassName() );
	this->m_ui->cmbSandEncoders->clear();
	for ( std::vector<std::string>::const_iterator it=encoders_name.begin(); it!=encoders_name.end(); ++it )
		this->m_ui->cmbSandEncoders->addItem( (*it).c_str() );
	
 }

void FormPersistenceManager::btnSandObjectDestroy_clicked() {
	if ( this->sand_obj == NULL ) {
		QMessageBox::warning(this, tr("Destroy SandObject.."), tr("FAILED. No allocated object found.") );
		return;
	 }
	WRESULT ret = ObjectFactory::destroy(this->sand_obj);
	this->sand_obj = NULL;
	this->m_ui->lblSandObjectStatus->setText( tr("Status: IDLE") );
	this->m_ui->cmbSandEncoders->clear();
	if ( WFAILED(ret) )
		QMessageBox::critical(this, tr("Destroy SandObject.."), tr("FAILED. Error#%1 destroying object.").arg(ret) );

 }

void FormPersistenceManager::btnSandObjectGui_clicked() {
	
	DialogSerializableEditor dialog;
	WRESULT ret = dialog.loadObject( this->sand_obj );
	if ( WFAILED(ret) ) {

	 }
	if ( dialog.exec() == QDialog::Accepted )
		dialog.saveObject( this->sand_obj );

/*
	if ( this->sand_obj == NULL ) {
		QMessageBox::warning(this, tr("Create GUI.."), tr("FAILED. No allocated object found.") );
		return;
	 }
	if ( this->sand_obj_gui != NULL ) {
		this->sand_obj_gui->loadObject(this->sand_obj);
		this->sand_obj_gui->asQWidget()->show();
		return;
	 }

	this->sand_obj_gui = GuiUtilities::createGuiFor<IWidgetSerializable>(this->sand_obj->getClassName());
	if ( this->sand_obj_gui == NULL ) {
		QMessageBox::warning(this, tr("Create GUI.."), tr("FAILED. No Widget found.") );
		return;
	 }
	this->sand_obj_gui->loadObject(this->sand_obj);
	this->sand_obj_gui->asQWidget()->show();
	//
	*/
 }

void FormPersistenceManager::btnSandToString_clicked() {
	if ( this->sand_obj == NULL ) {
		QMessageBox::warning(this, tr("ToString SandObject.."), tr("FAILED. No allocated object found.") );
		return;
	 }
	std::string data = this->sand_obj->toString();
	this->m_ui->txtSandDump->setPlainText( QString(data.c_str()) );
}

void FormPersistenceManager::btnSandEncode_clicked() {
	if ( this->sand_obj == NULL ) {
		QMessageBox::warning(this, tr("Encode SandObject.."), tr("FAILED. No allocated object found.") );
		return;
	 }
	checkAllocateSandBuffer();
	std::string encoder_protocol = this->m_ui->cmbSandEncoders->currentText().toStdString();
	int64 ret = PersistenceManager::serializeTo( this->sand_obj, encoder_protocol.c_str(), this->sand_buffer, this->sand_buffer_size, this->m_ui->chkSandEncodeCompact->isChecked() );
	this->m_ui->txtSandDump->clear();
	if ( ret <= 0 ) {
		return;
	 }
	this->m_ui->txtSandDump->setPlainText( QString(this->sand_buffer) );
}

void FormPersistenceManager::btnSandDecode_clicked() {
	if ( this->sand_obj == NULL ) {
		QMessageBox::warning(this, tr("Decode SandObject.."), tr("FAILED. No allocated object found.") );
		return;
	 }
	checkAllocateSandBuffer();
	std::string encoder_protocol = this->m_ui->cmbSandEncoders->currentText().toStdString();

//	int64 ret = PersistenceManager::deserializeFrom( this->sand_obj, encoder_protocol.c_str(), this->sand_buffer, this->sand_buffer_size, this->m_ui->chkSandEncodeCompact->isChecked() );

 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void FormPersistenceManager::buildMenus() {
	this->menuDataBasesTitle = new QAction(this);
	this->menuDataBasesTitle->setEnabled(false);
	this->menuDataBases = new QMenu(this);
	this->menuDataBases->addAction(this->menuDataBasesTitle);
	this->menuDataBases->addSeparator();

	this->menuProtocolTitle = new QAction(this);
	this->menuProtocolTitle->setEnabled(false);
	this->menuProtocolCreateGui = new QAction(this);
	this->menuProtocolCreateGui->setText(tr("&Create Gui.."));
	this->menuProtocolStart = new QAction(this);
	this->menuProtocolStart->setText(tr("&Start.."));
	this->menuProtocolStop = new QAction(this);
	this->menuProtocolStop->setText(tr("S&top.."));
	this->menuProtocol = new QMenu(this);
	this->menuProtocol->addAction(this->menuProtocolTitle);
	this->menuProtocol->addSeparator();
	this->menuProtocol->addAction(this->menuProtocolStart);
	this->menuProtocol->addAction(this->menuProtocolStop);
	this->menuProtocol->addSeparator();
	this->menuProtocol->addAction(this->menuProtocolCreateGui);
 }

void FormPersistenceManager::tableViewDataBases_ContextMenu( const QPoint& pos, const QModelIndex& index ) {
	QPoint globalPos = this->mapToGlobal(pos);
	if ( !index.isValid() || index.row() == 0 ) return;
	Variant dbName = this->m_ui->tableViewDataBases->getCurrentItemAsVariantAtCol(0);
	Variant dbType = this->m_ui->tableViewProtocols->getCurrentItemAsVariantAtCol(1);

	this->menuDataBasesTitle->setText( dbName.toString().c_str() );
	this->menuDataBasesTitle->setIcon( GuiUtilities::createIconFor(dbType.toString()) );
//	QAction* selected = this->menuDataBases->exec( globalPos );
 }

void FormPersistenceManager::tableViewProtocols_ContextMenu( const QPoint& pos, const QModelIndex& index ) {
	QPoint globalPos = this->mapToGlobal(pos);
	if ( !index.isValid() || index.row() == 0 ) return;
	Variant bundleName = this->m_ui->tableViewProtocols->getCurrentItemAsVariantAtCol(0);
	Variant bundleType = this->m_ui->tableViewProtocols->getCurrentItemAsVariantAtCol(1);
	Variant bundleState = this->m_ui->tableViewProtocols->getCurrentItemAsVariantAtCol(2);

	this->menuProtocolTitle->setText( bundleName.toString().c_str() );
	this->menuProtocolTitle->setIcon( GuiUtilities::createIconFor(bundleType.toString()) );
	if ( bundleState.toString() == "STARTED" ) {
		this->menuProtocolStart->setEnabled(false);
		this->menuProtocolStop->setEnabled(true);
	 } else {
		this->menuProtocolStart->setEnabled(true);
		this->menuProtocolStop->setEnabled(false);
	 }

	QAction* selected = this->menuProtocol->exec( globalPos );
	if ( selected == this->menuProtocolCreateGui ) {
	
	 }
	else if ( selected == this->menuProtocolStart ) {
		List* args = new List(2);
		args->push_back( bundleName.clone() );
		args->push_back<Variant>( "start" );
//		executeRemoteMethod( _PersistenceManager_METHOD_control_bundle, args );
	 }
	else if ( selected == this->menuProtocolStop ) {
		List* args = new List(2);
		args->push_back( bundleName.clone() );
		args->push_back<Variant>( "stop" );
//		executeRemoteMethod( _PersistenceManager_METHOD_control_bundle, args );
	 }
 }
 
/*
void FormPersistenceManager::tableViewSupportedProtocols_ContextMenu( const QPoint& pos, const QModelIndex& index ) {
	QPoint globalPos = this->mapToGlobal(pos);
	QModelIndex index = this->m_ui->tableViewSupportedProtocols->indexAt(pos);
	if ( !index.isValid() )
		return;
	Variant bundleType = this->m_ui->tableViewSupportedProtocols->getCurrentItemAsVariantAtCol(0);

	this->menuProtocolTitle->setText( bundleType.toString().c_str() );
	this->menuProtocolTitle->setIcon( GuiUtilities::createIconFor(bundleType.toString()) );

	QAction* selected = this->menuProtocol->exec( globalPos );
	if ( selected == this->menuProtocolCreateGui ) {
	 }
 }
*/
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void FormPersistenceManager::busMessage( const Message& message, const Bus* ) {
	if ( message.isEmpty() || !message.getContent()->isResponse() ) return;
	if ( !isMessageForMeOrFromTarget(message) ) return;
	const wosh::Response* response = message.getContent()->asResponse();

	if ( response->getMethod() == _METHOD_List && message.getSource().getPath().back() == "Protocols" ) {
		this->m_ui->tableViewEncoders->evalResponse(response);
	 }

	this->m_ui->tableViewDataBases->evalResponse(response);
	this->m_ui->tableViewProtocols->evalResponse(response);
	this->m_ui->tableViewSupportedProtocols->evalResponse(response);

	promptMethodResponse( message, false );

//	if ( response->getMethod() == _PersistenceManager_METHOD_control_bundle && WSUCCEEDED(response->getReturnValue()) ) {
//		refreshProtocols();
//	 }
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

 }; // namespace gui
}; // namespace wosh
